package service.impl;

import cn.tedu.csmall.commons.ex.ServiceException;
import cn.tedu.csmall.commons.pojo.vo.PageData;
import cn.tedu.csmall.commons.util.PageInfoToPageDataConverter;
import cn.tedu.csmall.commons.web.ServiceCode;
import cn.tedu.csmall.product.mapper.BrandCategoryMapper;
import cn.tedu.csmall.product.mapper.CategoryAttributeTemplateMapper;
import cn.tedu.csmall.product.mapper.CategoryMapper;
import cn.tedu.csmall.product.mapper.SpuMapper;
import cn.tedu.csmall.product.pojo.entity.BrandCategory;
import cn.tedu.csmall.product.pojo.entity.Category;
import cn.tedu.csmall.product.pojo.entity.CategoryAttributeTemplate;
import cn.tedu.csmall.product.pojo.entity.Spu;
import cn.tedu.csmall.product.pojo.param.CategoryAddNewParam;
import cn.tedu.csmall.product.pojo.param.CategoryUpdateInfoParam;
import cn.tedu.csmall.product.pojo.vo.CategoryListItemVO;
import cn.tedu.csmall.product.pojo.vo.CategoryStandardVO;
import cn.tedu.csmall.product.pojo.vo.CategoryTreeItemVO;
import cn.tedu.csmall.product.service.CategoryService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper mapper;
    @Autowired
    private BrandCategoryMapper brandCategoryMapper;
    @Autowired
    private CategoryAttributeTemplateMapper categoryAttributeTemplateMapper;
    @Autowired
    private SpuMapper spuMapper;

    @Override
    public void addNew(CategoryAddNewParam categoryAddNewParam) {
        log.info("开始:【新增类别】");
        log.debug("传入参数,categoryAddNewParam={}", categoryAddNewParam);
        //检查类别名称是否被占用，如果被占用，则抛出异常
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name",categoryAddNewParam.getName());
        queryWrapper.eq("parent_id",categoryAddNewParam.getParentId());
        int countByName = mapper.selectCount(queryWrapper);
        log.info("业务：根据类别名称检索数据库结果,countByName={}", countByName);
        if(countByName > 0){
            log.info("结果2:不满足类别新增规则【同父级类别下不能有相同名称】，抛出自定异常...");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "添加类别失败，类别名称已经被占用！");
        }

        Long parentId = categoryAddNewParam.getParentId();
        CategoryStandardVO standardById = null;
        Integer depth = 1;
        if(parentId != 0){
            standardById = mapper.getStandardById(parentId);
            log.info("业务：根据ID检索父级类别结果,standardById={}", standardById);
            if(standardById == null){
                String message = "新增类别失败，父级类别不存在";
                log.info("结果3:不满足类别新增规则【父级类别必须存在或为0】，抛出自定异常...");
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }else{
                depth = standardById.getDepth() + 1;
            }
        }

        log.info("满足类别新增规则，开始新增...");
        //名称未占用，添加类别到数据库
        Category category = new Category();
        BeanUtils.copyProperties(categoryAddNewParam,category);
        category.setDepth(depth)
                .setIsParent(0)
                .setGmtCreate(LocalDateTime.now())
                .setGmtModified(LocalDateTime.now());
        log.debug("添加类别数据,category={}", category);
        int rows = mapper.insert(category);
        if(rows != 1){
            String message = "添加类别失败，服务器忙，请稍后再试！";
            log.info("结果1:数据返回行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.info("结果1:新增类别结果,rows={}", rows);

        if(parentId != 0 && standardById.getIsParent() == 0){
            Category parentCategory = new Category();
            parentCategory.setId(parentId);
            parentCategory.setIsParent(1);
            rows = mapper.updateById(parentCategory);
            if (rows != 1) {
                String message = "添加类别失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_UPDATE, message);
            }
        }
    }

    @Override
    public void deleteById(Long id) {
        log.info("开始:【删除类别】");
        log.debug("传入参数,id={}", id);

        //检查类别ID检查类别是否存在数据，如果不存在，则抛出异常
        CategoryStandardVO categoryStandardVO = mapper.getStandardById(id);
        log.info("规则：根据类别id检索数据库结果,categoryStandardVO={}", categoryStandardVO);
        if(categoryStandardVO == null){
            String message = "删除类别失败，类别数据不存在！";
            log.info("结果2:根据类别id检索数据量为0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        //检查类别是否为父级，如果是，则抛出异常
        log.info("规则：根据类别是否为父类,isParent={}", categoryStandardVO.getIsParent());
        if(categoryStandardVO.getIsParent() == 1){
            String message = "删除类别失败，该类别为父级！";
            log.info("结果3:类别为父级不能能删除，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        
        //根据类别ID检查属性表是否存在数据，如果存在，则抛出异常
        QueryWrapper<BrandCategory> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.eq("category_id", id);
        int countByCategoryId4 = brandCategoryMapper.selectCount(queryWrapper4);
        log.info("规则：根据类别id检索类别类别关系数据库结果,countByCategoryId4={}", countByCategoryId4);
        if(countByCategoryId4 > 0){
            String message = "删除类别失败，品牌类别表内有关联数据！";
            log.info("结果4:根据类别id检索属性数据量>0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //根据类别ID检查类别模板表是否存在数据，如果存在，则抛出异常
        QueryWrapper<CategoryAttributeTemplate> queryWrapper5 = new QueryWrapper<>();
        queryWrapper5.eq("category_id", id);
        int countByCategoryId5 = categoryAttributeTemplateMapper.selectCount(queryWrapper5);
        log.info("规则：根据类别id检索类别模板表数据库结果,countByCategoryId5={}", countByCategoryId5);
        if(countByCategoryId5 > 0){
            String message = "删除类别失败，类别模板表内存在该类别数据！";
            log.info("结果5:根据类别id检索类别模板表数据量>0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //根据类别ID检查Spu是否存在数据，如果存在，则抛出异常
        QueryWrapper<Spu> queryWrapper6 = new QueryWrapper<>();
        queryWrapper6.eq("category_id", id);
        int countByCategoryId6 = spuMapper.selectCount(queryWrapper6);
        log.info("规则：根据类别id检索spu数据库结果,countByCategoryId6={}", countByCategoryId6);
        if(countByCategoryId6 > 0){
            String message = "删除类别失败，spu内存在该类别数据！";
            log.info("结果6:根据类别id检索spu数据量>0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        int rows = mapper.deleteById(id);
        if(rows != 1){
            String message = "删除类别失败，服务器忙，请稍后再试！";
            log.info("结果1:数据返回行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        log.info("结果1:删除类别结果,rows={}", rows);

        //判断是否修改父级
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", categoryStandardVO.getParentId());
        Integer count = mapper.selectCount(queryWrapper);
        if(count == 0){
            Category parentCategory = new Category();
            parentCategory.setId(categoryStandardVO.getParentId());
            parentCategory.setIsParent(0);
            rows = mapper.updateById(parentCategory);
            if (rows != 1) {
                String message = "删除类别失败，服务器忙，请稍后再尝试！";
                log.info("结果1:父级类别修改行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
                throw new ServiceException(ServiceCode.ERR_UPDATE, message);
            }
            log.info("结果1:修改父级类别结果,rows={}", rows);
        }
    }

    @Override
    public void updateInfoById(Long id, CategoryUpdateInfoParam categoryUpdateInfoParam) {
        log.info("开始:【根据id更新类别】");
        log.debug("传入参数,id={},categoryUpdateInfoParam={}", id, categoryUpdateInfoParam);

        //检查类别ID检查类别是否存在数据，如果不存在，则抛出异常
        CategoryStandardVO categoryStandardVO = mapper.getStandardById(id);
        log.info("规则：根据类别id检索数据库结果,categoryStandardVO={}", categoryStandardVO);
        if(categoryStandardVO == null){
            String message = "更新类别失败，类别数据不存在！";
            log.info("结果2:根据类别id检索数据量为0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        //检查类别名称是否被占用，如果被占用，则抛出异常
        QueryWrapper<Category> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("name",categoryUpdateInfoParam.getName());
        queryWrapper3.eq("parent_id",categoryStandardVO.getParentId());
        int countByName = mapper.selectCount(queryWrapper3);
        log.info("业务：根据类别名称检索数据库结果,countByName={}", countByName);
        if(countByName > 0){
            log.info("结果3:不满足类别更新规则【同父级类别下不能有相同名称】，抛出自定异常...");
            String message = "更新类别失败，类别名称已经被占用！";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Category category = new Category();
        BeanUtils.copyProperties(categoryUpdateInfoParam, category);
        category.setId(id);
        int rows = mapper.updateById(category);
        if(rows != 1){
            String message = "编辑类别失败，服务器忙，请稍后再试！";
            log.info("结果1:数据返回行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        log.info("结果1:根据id更新类别结果,rows={}", rows);
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id, 0);
    }

    private void updateEnableById(Long id, Integer enable){
        String text = ENABLE_TEXT[enable];
        log.info("开始:【" + text + "类别】");
        log.debug("传入参数,id={}, enable={} ", id, enable);

        //检查数据是否存在，如果不存在，则抛出异常
        CategoryStandardVO categoryStandardVO = mapper.getStandardById(id);
        log.info("规则：根据类别id检索数据库结果,categoryStandardVO={}", categoryStandardVO);
        if(categoryStandardVO == null){
            String message = text + "类别失败，类别数据不存在！";
            log.info("结果2:根据类别id检索数据量为0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        if(categoryStandardVO.getEnable() == enable){
            String message = text + "类别失败，此类别已经处于" + text + "状态！";
            log.info("结果3:根据类别启用状态与要修改状态一致，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Category category = new Category();
        category.setId(id).setEnable(enable);
        int rows = mapper.updateById(category);
        if(rows != 1){
            String message = text+"类别失败，服务器忙，请稍后再试！";
            log.info("结果1:数据返回行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        log.info("结果1:根据id更新类别结果,rows={}", rows);
    }

    @Override
    public void setDisplay(Long id) {
        updateDisplayById(id, 1);
    }

    @Override
    public void setHidden(Long id) {
        updateDisplayById(id, 0);
    }
    
    private void updateDisplayById(Long id, Integer isDisplay){
        String text = DISPLAY_TEXT[isDisplay];
        log.info("开始:【" + text + "类别】");
        log.debug("传入参数,id={}, isDisplay={} ", id, isDisplay);

        //检查数据是否存在，如果不存在，则抛出异常
        CategoryStandardVO categoryStandardVO = mapper.getStandardById(id);
        log.info("规则：根据类别id检索数据库结果,categoryStandardVO={}", categoryStandardVO);
        if(categoryStandardVO == null){
            String message = text + "类别失败，类别数据不存在！";
            log.info("结果2:根据类别id检索数据量为0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        if(categoryStandardVO.getIsDisplay() == isDisplay){
            String message = text + "类别失败，此类别已经处于" + text + "状态！";
            log.info("结果3:类别启用状态与要修改状态一致，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Category category = new Category();
        category.setId(id).setIsDisplay(isDisplay);
        int rows = mapper.updateById(category);
        if(rows != 1){
            String message = text+"类别失败，服务器忙，请稍后再试！";
            log.info("结果1:数据返回行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        log.info("结果1:根据id更新类别结果,rows={}", rows);
    }

    @Override
    public CategoryStandardVO getStandardById(Long id) {
        log.info("开始:【根据ID查询类别】");
        log.debug("传入参数,id={}", id);
        CategoryStandardVO standardById = mapper.getStandardById(id);

        //根据类别ID检查类别是否存在数据，如果不存在，则抛出异常
        if(standardById==null){
            log.info("结果2:根据类别id查询详情，结果为null，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "查询类别详情失败，类别数据不存在");
        }

        log.info("结果1:查询出数据,standardById");
        return standardById;
    }


    @Override
    public List<CategoryListItemVO> listByParentId(Long parentId) {
        List<CategoryListItemVO> categoryListItemVOS = mapper.listByParentId(parentId);
        return categoryListItemVOS;
    }

    @Override
    public PageData<CategoryListItemVO> listByParentId(Long parentId, Integer pageNum) {
        Integer pageSize = 5;
        return listByParentId(parentId, pageNum, pageSize);
    }

    @Override
    public PageData<CategoryListItemVO> listByParentId(Long parentId, Integer pageNum, Integer pageSize) {
        log.info("开始:【查询-类别-分页】");
        log.debug("传入参数, parentId={}, pageNum={}, pageSize={}", parentId, pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<CategoryListItemVO> list = mapper.listByParentId(parentId);
        PageInfo<CategoryListItemVO> pageInfo = new PageInfo<>(list);
        PageData<CategoryListItemVO> pageData = PageInfoToPageDataConverter.converter(pageInfo);
        log.debug("结果1: 查询结果：pageData={}", pageData);
        return pageData;
    }

    @Override
    public List<CategoryTreeItemVO> listTree() {
        //由数据库获取全部类别对象
        List<CategoryListItemVO> categoryList = mapper.list();
        //将List封装为Map,KEY为父级ID，VALUE为parentId为key,类别分组的List
        Map<Long, List<CategoryTreeItemVO>> allCategoryMap = transformListToMap(categoryList);
        //获取顶级树节点列表
        Long id = 0L;
        List<CategoryTreeItemVO> topTreeList = allCategoryMap.get(id);
        //遍历所有顶级节点
        for (CategoryTreeItemVO categoryTreeItemVO : topTreeList) {
            //装入节点的子节点集合
            fillChildren(categoryTreeItemVO, allCategoryMap);
        }
        return topTreeList;
    }

    /**
     * 使用递归，不断查找传入节点的子节点列表
     * @param categoryTreeItemVO
     * @param allCategoryMap
     */
    private void fillChildren(CategoryTreeItemVO categoryTreeItemVO, Map<Long, List<CategoryTreeItemVO>> allCategoryMap) {
        //根节点，无法获取子节点列表，表示该节点不是父节点
        List<CategoryTreeItemVO> subTreeList = allCategoryMap.get(categoryTreeItemVO.getValue());
        if(subTreeList == null){
            return;
        }
        for (CategoryTreeItemVO treeItemVO : subTreeList) {
            fillChildren(treeItemVO, allCategoryMap);
        }
        categoryTreeItemVO.setChildren(subTreeList);
    }

    /**
     * 以parentId为key,将类别分组
     * @param categoryList
     * @return
     */
    private Map<Long, List<CategoryTreeItemVO>> transformListToMap(List<CategoryListItemVO> categoryList){
        //以parentId为key,将类别分组
        Map<Long, List<CategoryTreeItemVO>> categoryListMap = new HashMap<>();
        //遍历所有类别
        for (CategoryListItemVO categoryListItemVO : categoryList) {
            //禁用的直接跳过
            if(categoryListItemVO.getEnable() == 0){
                continue;
            }
            //以该类别父级ID为key的集合
            List<CategoryTreeItemVO> categoryListTree = null;
            //Map中存在,直接取出
            if(categoryListMap.containsKey(categoryListItemVO.getParentId())){
                categoryListTree = categoryListMap.get(categoryListItemVO.getParentId());
            }else{
                //不存在,创建新集合
                categoryListTree = new ArrayList<>();
            }
            //转换为Tree的类,并装入集合
            CategoryTreeItemVO categoryTreeItemVO = new CategoryTreeItemVO();
            categoryTreeItemVO.setLabel(categoryListItemVO.getName())
                    .setValue(categoryListItemVO.getId());
            //装入List
            categoryListTree.add(categoryTreeItemVO);
            //装入Map
            categoryListMap.put(categoryListItemVO.getParentId(), categoryListTree);
        }
        return categoryListMap;
    }
}
